package cn.ami01.controller;

import cn.ami01.entity.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.jws.WebParam;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;

/**
 * springMVC的测试类
 * Created by zhangzejun on 2016/11/25.
 */

// sessionAttributes中value的值  如果下面有map.put()一类的方法，也会一起放到session中去
@SessionAttributes(value={"user"},types={String.class})
@RequestMapping("springmvc")
@Controller
public class springMVCTest {
    private static final String SUCCESS = "success";

    @RequestMapping("/testRedirect")
    public String testRedirect(){
        System.out.println("testRedirect");
        return "redirect:/index.jsp";
    }

    @RequestMapping("/testView")
    public String testView(){
        System.out.println("testView");
        return "helloView";
    }

    @RequestMapping("/testViewAndResolver")
    public String testViewAndResolver(){
        System.out.println("testViewAndResolver");
        return SUCCESS;
    }

    /**
     * 1、有@ModelAttribute标记的方法会在每个目标方法执行之前被springmvc调用
     * 2、@ModelAttribute 注解也可以用来修饰目标方法POJO类型的入残，其value属性值有如下的作用：
     * 1).SpringMVC会使用value属性值在implicitModel中查找对应的对象，若存在，则会直接传入到目标方法的入参中
     * 2).SpringMVC会以value为key，POJO类型的对象为value，存入到request中。
     * @param id
     * @param map
     */
    @ModelAttribute
    public void getUser(@RequestParam(value = "id",required = false)Integer id,Map<String,Object> map){
        System.out.println("modelAttribute method");
        if(id != null){
            //模拟从数据库中获取对象
            User user = new User(1,"Tom","123456","tom@163.com",12);
            System.out.println("从数据库中获取一个对象："+user);
            map.put("user",user);

            //如果这里的map.put("abc",user);那么下面的testModelAttribute()方法这么写：testModelAttribute(@ModelAttribute("abc") User user)
        }
    }

    /**
     * 运行流程：
     * 1.执行@ModelAttribute注解修饰的方法：从数据库中取出对象，把对象放入到了Map中。 键为：user
     * 2.SpringMVC 从Map中取出User对象，并把表单的请求参数赋给该User对象的对应属性。
     * 3.SpringMVC 把上述对象传入目标方法的参数
     *
     * 注意：在@ModelAttribute修饰的方法中，放入到Map时的键 需要和目标方法参数的第一个字母小写的字符串一致
     * @param user
     * @return
     */
    @RequestMapping("/testModelAttribute")
    public String testModelAttribute(User user){
        System.out.println("修改："+user);
        return SUCCESS;
    }

    /**
     * @SessionAttributes 除了可以通过属性名指定需要放到会话中的属性外（实际上使用的value属性值）
     * 还可以通过模型属性的对象类型指定那些模型属性需要放到会话中（实际上使用的是types属性值）
     *
     * 需要注意的是  这个注解只能放在类上边  不能放在方法的上边
     * @return
     */
    @RequestMapping("/testSessionAttributes")
    public String testSessionAttributes(Map<String,Object> map){
        User user = new User(1,"Tom","123456","tom@126.com",15);
        map.put("user",user);
        map.put("school","HHIT"); //这里school是String.class所以也会被一起加到session中
        return SUCCESS;
    }

    /**
     * 目标方法可以添加Map类型（实际上也可以是Model或者ModelMap类型）的参数
     * @param map
     * @return
     */
    @RequestMapping("/testMap")
    public String testMap(Map<String,Object> map){
        //System.out.println(map.getClass().getName());
        map.put("names", Arrays.asList("Tom","Jerry","Snooby"));
        return SUCCESS;
    }

    /**
     * 目標方法的返回值可以是ModelAndView類型。
     * 其中可以包含视图和模型信息
     * SpringMVC会把ModelAndView中的model中的数据放到request域对象中
     * @return
     */
    @RequestMapping("/testModelAndView")
    public ModelAndView testModelAndView(){
        String viewName = SUCCESS;
        ModelAndView modelAndView = new ModelAndView(viewName);
        modelAndView.addObject("time",new Date());
        return modelAndView;
    }

    /**
     *HttpServletRequest
     * HttpServletResponse
     * HttpSession
     * java.security.Principal
     * Locale InputStream
     * OutputStream
     * Reader
     * Writer
     * @return
     */
    @RequestMapping("/testServletAPI")
    public String testServletAPI(HttpServletRequest request, HttpServletResponse response){
        System.out.println("testServletAPI:"+request+","+response);
        return SUCCESS;
    }

    /**
     *Spring MVC 会按照请求参数名和POJO属性名进行自动匹配
     * 自动为该对象填充属性值，支持级联属性
     * 如：dept.deptId、dept.address.tel等
     * @return
     */
    @RequestMapping("/testPojo")
    public String testPojo(User user){
        System.out.println("User:"+user);
        return SUCCESS;
    }

    /**
     * @CookieValue 映射一个Cookie值，属性同@RequestParam
     * @param sessionId
     * @return
     */
    @RequestMapping("/testCookieValue")
    public String testCookieValue(@CookieValue("JSESSIONID") String sessionId){
        System.out.println("testCookieValue:"+sessionId);
        return SUCCESS;
    }

    /**
     * 映射请求头信息，用法通@RequestParam
     * @param a1
     * @return
     */
    @RequestMapping("/testRequestHeader")
    public String testRequestHeader(@RequestHeader(value="Accept-Language") String a1){
        System.out.println("testRequestHeader,Accept-Language:"+a1);
        return SUCCESS;
    }

    /**
     *@RequestParam(value="username") 这个value可以省略
     *@RequestParam 来映射请求参数
     * value值即请求参数的参数名
     * required 该参数是否必须，默认为true
     * defaultValue 是请求参数的默认值
     * @param username
     * @param age
     * @return
     */
    @RequestMapping(value = "/testRequestParam")
    public String testRequestParam(@RequestParam("username") String username,@RequestParam(value="age",required=false,defaultValue = "0") Integer age){
        System.out.println("testRequestParam,username="+username+"age="+age);
        return SUCCESS;
    }

    /**
     * 如何使用PUT 和DELETE 方法
     * tomcat8 好像不支持put和delete方法
     * 1.配置HiddenHttpMethodFilter
     * 2.需要发送POST请求
     * 3.需要在发送POST请求时携带一个 name="_method" value="put或者delete" 的隐藏域
     * 在SpringMVC的目标方法中如何得到id呢？  使用@PathVariable注解
     * @param id
     * @return
     */
    @RequestMapping(value="/testRestful/{id}",method = RequestMethod.PUT)
    public String testRestfulPut(@PathVariable("id") Integer id){
        System.out.println("testRestfulPut:"+id);
        return SUCCESS;
    }

    @RequestMapping(value="/testRestful/{id}",method = RequestMethod.DELETE)
    public String testRestfulDelete(@PathVariable("id") Integer id){
        System.out.println("testRestfulDelete:"+id);
        return SUCCESS;
    }

    @RequestMapping(value="/testRestful",method = RequestMethod.POST)
    public String testRestful(){
        System.out.println("testRestfulPost:");
        return SUCCESS;
    }

    @RequestMapping(value="/testRestful/{id}",method = RequestMethod.GET)
    public String testRestful(@PathVariable("id") Integer id){
        System.out.println("testRestfulGet:"+id);
        return SUCCESS;
    }
    /**
     * @PathVariable 可以来映射URL中的占位符到目标方法的参数中
     * @param id
     * @return
     */
    @RequestMapping(value="/testPathVariable/{id}")
    public String testPathVariable(@PathVariable(value="id") Integer id){
        System.out.println("testPathVariable:"+id);
        return SUCCESS;
    }

    /**
     * @RequestMapping() 支持通配符的情况
     * @return
     */
    @RequestMapping("/testAntPath/*/abc")
    public String testAntPath(){
        System.out.println("testAntPath");
        return SUCCESS;
    }

    /**
     * 了解：可以使用params和headers来更加精确地映射请求，params和headers支持简单的表达式
     * @return
     */
    @RequestMapping(value="/testParamsAndHeads",params = {"username","age!=10"},headers = {"Accept-Language=zh-CN,zh;q=0.8"})
    public String testParamsAndHeads(){
        System.out.println("testParamsAndHeads");
        return SUCCESS;
    }

    /**
     * 使用method属性来指定请求方式
     * @return
     */
    @RequestMapping(value = "/testMethod",method = RequestMethod.POST)
    public String testMethod(){
        System.out.println("testMethod");
        return SUCCESS;
    }
    /**
     * 1、RequestMapping()除了可以修饰方法还可以修饰类
     * 2、1).类定义处：提供初步的请求映射信息，相对于WEB应用的根目录
     *    2).方法处：提供进一步的细分映射信息，相对于类定义处的URL。若类定义处未标注@RequestMapping，则方法处标记的URL相对于WEB应用的根目录
     * @return
     */
    @RequestMapping("/testRequestMapping")
    public String testRequestMapping(){
        System.out.println("testRequestMapping");
        return SUCCESS;
        /*
            ModelAndView的一种方法，使用时候注意改方法类型
            ModelAndView mv = new ModelAndView();
            mv.addObject("username","ligoudan");
            mv.setViewName("success");
            return mv;
        */
    }
}






































